4using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using Microsoft.Ccr.Adapters.Wpf;
using System.Windows;

namespace KinectCamViewer
{
    [Contract(Contract.Identifier)]
    [DisplayName("KinectCamViewer")]
    [Description("KinectCamViewer service (no description provided)")]
    class KinectCamViewerService : DsspServiceBase
    {
        [ServiceState]
        KinectCamViewerState _state = new KinectCamViewerState();

        [ServicePort("/KinectCamViewer", AllowMultipleInstances = true)]
        KinectCamViewerOperations _mainPort = new KinectCamViewerOperations();

        public KinectCamViewerService(DsspServiceCreationPort creationPort)
        : base(creationPort)
        {
        }

        WpfServicePort _wpfServicePort;
        KinectCamViewerUI _wpfUI;
        bool activeTiming = false;
        Port<DateTime> _timingPort = new Port<DateTime>();

        protected override void Start()
        {
            SpawnIterator(Initialize);
        }

        IEnumerator<ITask> Initialize()
        {
            #region Create UI
            // create WPF adapter
            _wpfServicePort = WpfAdapter.Create(TaskQueue);

            var runWindow = _wpfServicePort.RunWindow(() => new KinectCamViewerUI(_mainPort));
            yield return (Choice)runWindow;

            var exception = (Exception)runWindow;
            if (exception != null)
            {
                LogError(exception);
                StartFailed();
                yield break;
            }

            // need double cast because WPF adapter doesn't know about derived window types
            _wpfUI = (Window)runWindow as KinectCamViewerUI;
            #endregion

            StartComplete();
        }

        void StartComplete()
        {
            base.Start();

            Activate(Arbiter.Interleave(
                new TeardownReceiverGroup(
                    Arbiter.Receive<DsspDefaultDrop>(false, _mainPort, DropHandler)),
                new ExclusiveReceiverGroup(
                    Arbiter.ReceiveWithIterator<SetTiming>(true, _mainPort, SetTimingHandler)),
                new ConcurrentReceiverGroup(
                    )));

            DirectoryInsert();

            Activate(Arbiter.Receive(true, _timingPort, TimingHandler));
        }

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public virtual IEnumerator<ITask> SetTimingHandler(SetTiming update)
        {
            if (update.Body.IsActive)
            {
                if (!activeTiming)
                {
                    activeTiming = true;
                }

                Activate(
                    Arbiter.Receive(false, TimeoutPort(100),
                                    delegate(DateTime time)
                                    {
                                        _timingPort.Post(time);
                                    }));
            }
            else
            {
                activeTiming = false;
            }

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }

        void TimingHandler(DateTime time)
        {
            _wpfServicePort.Invoke(
                delegate()
                {
                    _wpfUI.Play();
                });
        }

        void DropHandler(DsspDefaultDrop drop)
        {
            if (_wpfUI != null)
            {
                _wpfServicePort.Invoke(
                    delegate()
                    {
                        _wpfUI.Close();
                    });

                base.DefaultDropHandler(drop);
            }
        }
    }
}